﻿// Copyright 2009 Mike Geise
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Falcon.Core.Validation
{
	using System;
	using System.Collections.Generic;
	using System.Linq.Expressions;
	using Falcon.Core.Validation.Validators;

	public class ValidationOption<T>
	{
		private readonly string _bind;
		private readonly IList<ValidationItem> _validators;

		/// <summary>
		/// Initializes a new instance of the <see cref="ValidationOption&lt;T&gt;"/> class.
		/// </summary>
		/// <param name="bind">The bind.</param>
		/// <param name="validators">The validators.</param>
		public ValidationOption(string bind, IList<ValidationItem> validators)
		{
			_bind = bind;
			_validators = validators;
		}

		public ValidationOption<T> NotEmpty(string error)
		{
			_validators.Add(new ValidationItem
        	{
				Validator = new NotEmptyValidator(), 
				Bind = _bind,
				Error = error
        	});

			return this;
		}

		public ValidationOption<T> Equal(Expression<Func<T, object>> func, string error)
		{
			var expression = (func.Body as MemberExpression);

			if (expression == null)
			{
				throw new ArgumentNullException("func");
			}

			_validators.Add(new ValidationItem
			{
				Validator = new EqualValidator(),
				Bind = _bind,
				Against = expression.Member.Name,
				Error = error
			});

			return this;
		}

		public ValidationOption<T> NotEqual(object value, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new NotEqualValidator(),
				Bind = _bind,
				Error = error,
				Value = value
			});

			return this;
		}

		public ValidationOption<T> NotEqual(Expression<Func<T, object>> func, string error)
		{
			var expression = (func.Body as MemberExpression);

			if (expression == null)
			{
				throw new ArgumentNullException("func");
			}

			_validators.Add(new ValidationItem
			{
				Validator = new NotEqualValidator(),
				Bind = _bind,
				Against = expression.Member.Name,
				Error = error
			});

			return this;
		}

		public ValidationOption<T> GreaterThan(object value, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new GreaterThanValidator(),
				Bind = _bind,
				Error = error,
				Value = value
			});

			return this;
		}

		public ValidationOption<T> EqualOrGreaterThan(object value, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new EqualOrGreaterThanValidator(),
				Bind = _bind,
				Error = error,
				Value = value
			});

			return this;
		}

		public ValidationOption<T> EqualOrLessThan(object value, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new EqualOrLessThanValidator(),
				Bind = _bind,
				Error = error,
				Value = value
			});

			return this;
		}

		public ValidationOption<T> LessThan(object value, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new LessThanValidator(),
				Bind = _bind,
				Error = error,
				Value = value
			});

			return this;
		}

		public ValidationOption<T> Between(object lower, object upper, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new BetweenValidator(),
				Bind = _bind,
				Error = error,
				Value = string.Concat(lower, ",", upper)
			});

			return this;
		}

		public ValidationOption<T> LengthGreaterThan(int value, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new LengthGreaterThanValidator(),
				Bind = _bind,
				Error = error,
				Value = value
			});

			return this;
		}

		public ValidationOption<T> LengthLessThan(int value, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new LengthLessThanValidator(),
				Bind = _bind,
				Error = error,
				Value = value
			});

			return this;
		}

		public ValidationOption<T> LengthBetween(int lower, int upper, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new LengthBetweenValidator(),
				Bind = _bind,
				Error = error,
				Value = string.Concat(lower, ",", upper)
			});

			return this;
		}

		public ValidationOption<T> Email(string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new EmailValidator(),
				Bind = _bind,
				Error = error
			});

			return this;
		}

		public ValidationOption<T> Characters(string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new CharactersValidator(),
				Bind = _bind,
				Error = error
			});

			return this;
		}

		public ValidationOption<T> Image(string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new ImageValidator(),
				Bind = _bind,
				Error = error
			});

			return this;
		}

		public ValidationOption<T> ImageDimensionMinimum(int width, int height, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new ImageDimensionMinimumValidator(),
				Bind = _bind,
				Value = string.Concat(width, ",", height),
				Error = error
			});

			return this;
		}

		public ValidationOption<T> ImageDimensionMaximum(int width, int height, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new ImageDimensionMaximumValidator(),
				Bind = _bind,
				Value = string.Concat(width, ",", height),
				Error = error
			});

			return this;
		}

		public ValidationOption<T> Date(string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = new DateValidator(),
				Bind = _bind,
				Error = error
			});

			return this;
		}

		public ValidationOption<T> Custom(IValidator validator, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = validator,
				Bind = _bind,
				Error = error
			});

			return this;
		}

		public ValidationOption<T> Custom(IValidator validator, string value, string error)
		{
			_validators.Add(new ValidationItem
			{
				Validator = validator,
				Bind = _bind,
				Value = value,
				Error = error
			});

			return this;
		}

		public ValidationOption<T> Custom(IValidator validator, Expression<Func<T, object>> func, string error)
		{
			var expression = (func.Body as MemberExpression);

			if (expression == null)
			{
				throw new ArgumentNullException("func");
			}

			_validators.Add(new ValidationItem
			{
				Validator = validator,
				Bind = _bind,
				Against = expression.Member.Name,
				Error = error
			});

			return this;
		}
	}
}